/**
 * Class used to send requests to the server and retreive the response.
 * The response can be either XML or plain text.
 *
 * @author Andrey Anisimov <hercules@inbox.ru>
 */

import core.ajax.Response;
import core.util.Listeners;

class Request {
	
	/**
	 * Constructs the new request object.
	 *
	 * @param url (string) The request url.
	 */
	this.Request = function(url) {
		this.url = url;
		this.listeners = new Listeners([
            'onRequestComplete',
            'onRequestError'
        ]);
		this.http = XMLHttpRequestFactory.createRequest();
		this.http.onreadystatechange = bind(this, this.onRequestStateChange);
	}

	/**
	 * Returns the request URL.
	 * @return string
	 */
	this.getUrl = function() {
		return this.url;
	}

	/**
	 * Adds the request listener.
	 *
	 * @param listener (object) The listener to add.
	 */
	this.addRequestListener = function(listener) {
		this.listeners.add(listener);
	}

	/**
	 * Removes the request listener.
	 *
	 * @param listener (object) The listener to remove.
	 */
	this.removeRequestListener = function(listener) {
		this.listeners.remove(listener);
	}

	/**
	 * Sends the request.
	 *
	 * @param params (object) [optional] The request parameters.
	 */
	this.send = function(params) {
		if (params) {
			var content = [];
			for (var name in params) {
				content.push(encodeURIComponent(name) + '=' + encodeURIComponent(params[name]));
			}
			this.http.open('POST', this.url, true);
			this.http.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
			this.http.send(content.join('&'));
		} else {
			this.http.open('GET', this.url, true);
			this.http.send(null);
		}
	}
	
	/**
	 * @protected
	 * Calls when request is complete.
 	 * 
	 * @param response (text/object/Response) The server response.
	 */
	this.fireComplete = function(response) {
		this.listeners.call('onRequestComplete', [ this, response ]);
	}
	
	/**
	 * @protected
	 * Calls when error occurs during request processing.
	 * 
	 * @param error (text/object/Response) error data object.
	 */
	this.fireError = function(error) {
		this.listeners.call('onRequestError', [ this, error ]);
	}
	
	this.onRequestStateChange = function() {
		if (4 == this.http.readyState) {
			
			if ((200 == this.http.status) || (304 == this.http.status)) {
				
				switch (this.http.getResponseHeader('Content-Type')) {

				case 'text/xml': 					
				case 'application/xml': 
					// XML response
					var rootNode;
					if (this.http.responseXML && (rootNode = this.http.responseXML.documentElement)) {
						rootNode.normalize();
						if ('response' == rootNode.nodeName) {
							this.fireComplete(new Response(rootNode));
						} else if ('error' == rootNode.nodeName) {
							this.fireError(new Response(rootNode));
						} else {
							this.fireError('Unsupported response format.');
						}
					}
					break;
				
				case 'text/json':
				case 'application/json':
					// JSON retrieved
					this.fireComplete(eval('(' + this.http.responseText + ')'));
					break;
					
				default: 
					// default is text/html
					this.fireComplete(this.http.responseText);
					break;
				}
			} else {
				this.fireError("There was a problem retrieving the XML data:\n" + this.http.statusText);
			}
		}
	}
}